<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Fourier Transform</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d6/d00/tutorial_py_root.html">OpenCV-Python Tutorials</a></li><li class="navelem"><a class="el" href="../../d2/d96/tutorial_py_table_of_contents_imgproc.html">Image Processing in OpenCV</a></li><li class="navelem"><a class="el" href="../../dd/dc4/tutorial_py_table_of_contents_transforms.html">Image Transforms in OpenCV</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Fourier Transform </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><h2>Goal </h2>
<p>In this section, we will learn</p><ul>
<li>To find the Fourier Transform of images using OpenCV</li>
<li>To utilize the FFT functions available in Numpy</li>
<li>Some applications of Fourier Transform</li>
<li>We will see following functions : <b><a class="el" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d" title="Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating-point array...">cv.dft()</a></b>, <b><a class="el" href="../../d2/de8/group__core__array.html#gaa708aa2d2e57a508f968eb0f69aa5ff1" title="Calculates the inverse Discrete Fourier Transform of a 1D or 2D array. ">cv.idft()</a></b> etc</li>
</ul>
<h2>Theory </h2>
<p>Fourier Transform is used to analyze the frequency characteristics of various filters. For images, <b>2D Discrete Fourier Transform (DFT)</b> is used to find the frequency domain. A fast algorithm called <b>Fast Fourier Transform (FFT)</b> is used for calculation of DFT. Details about these can be found in any image processing or signal processing textbooks. Please see Additional Resources_ section.</p>
<p>For a sinusoidal signal, \(x(t) = A \sin(2 \pi ft)\), we can say \(f\) is the frequency of signal, and if its frequency domain is taken, we can see a spike at \(f\). If signal is sampled to form a discrete signal, we get the same frequency domain, but is periodic in the range \([- \pi, \pi]\) or \([0,2\pi]\) (or \([0,N]\) for N-point DFT). You can consider an image as a signal which is sampled in two directions. So taking fourier transform in both X and Y directions gives you the frequency representation of image.</p>
<p>More intuitively, for the sinusoidal signal, if the amplitude varies so fast in short time, you can say it is a high frequency signal. If it varies slowly, it is a low frequency signal. You can extend the same idea to images. Where does the amplitude varies drastically in images ? At the edge points, or noises. So we can say, edges and noises are high frequency contents in an image. If there is no much changes in amplitude, it is a low frequency component. ( Some links are added to Additional Resources_ which explains frequency transform intuitively with examples).</p>
<p>Now we will see how to find the Fourier Transform.</p>
<h2>Fourier Transform in Numpy </h2>
<p>First we will see how to find Fourier Transform using Numpy. Numpy has an FFT package to do this. <b>np.fft.fft2()</b> provides us the frequency transform which will be a complex array. Its first argument is the input image, which is grayscale. Second argument is optional which decides the size of output array. If it is greater than size of input image, input image is padded with zeros before calculation of FFT. If it is less than input image, input image will be cropped. If no arguments passed, Output array size will be same as input.</p>
<p>Now once you got the result, zero frequency component (DC component) will be at top left corner. If you want to bring it to center, you need to shift the result by \(\frac{N}{2}\) in both the directions. This is simply done by the function, <b>np.fft.fftshift()</b>. (It is more easier to analyze). Once you found the frequency transform, you can find the magnitude spectrum. </p><div class="fragment"><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">from</span> matplotlib <span class="keyword">import</span> pyplot <span class="keyword">as</span> plt</div><div class="line"></div><div class="line">img = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<span class="stringliteral">&#39;messi5.jpg&#39;</span>,0)</div><div class="line">f = np.fft.fft2(img)</div><div class="line">fshift = np.fft.fftshift(f)</div><div class="line">magnitude_spectrum = 20*np.log(np.abs(fshift))</div><div class="line"></div><div class="line">plt.subplot(121),plt.imshow(img, cmap = <span class="stringliteral">&#39;gray&#39;</span>)</div><div class="line">plt.title(<span class="stringliteral">&#39;Input Image&#39;</span>), plt.xticks([]), plt.yticks([])</div><div class="line">plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = <span class="stringliteral">&#39;gray&#39;</span>)</div><div class="line">plt.title(<span class="stringliteral">&#39;Magnitude Spectrum&#39;</span>), plt.xticks([]), plt.yticks([])</div><div class="line">plt.show()</div></div><!-- fragment --><p> Result look like below:</p>
<div class="image">
<img src="../../fft1.jpg" alt="fft1.jpg"/>
<div class="caption">
image</div></div>
<p> See, You can see more whiter region at the center showing low frequency content is more.</p>
<p>So you found the frequency transform Now you can do some operations in frequency domain, like high pass filtering and reconstruct the image, ie find inverse DFT. For that you simply remove the low frequencies by masking with a rectangular window of size 60x60. Then apply the inverse shift using <b>np.fft.ifftshift()</b> so that DC component again come at the top-left corner. Then find inverse FFT using <b>np.ifft2()</b> function. The result, again, will be a complex number. You can take its absolute value. </p><div class="fragment"><div class="line">rows, cols = img.shape</div><div class="line">crow,ccol = rows//2 , cols//2</div><div class="line">fshift[crow-30:crow+31, ccol-30:ccol+31] = 0</div><div class="line">f_ishift = np.fft.ifftshift(fshift)</div><div class="line">img_back = np.fft.ifft2(f_ishift)</div><div class="line">img_back = np.real(img_back)</div><div class="line"></div><div class="line">plt.subplot(131),plt.imshow(img, cmap = <span class="stringliteral">&#39;gray&#39;</span>)</div><div class="line">plt.title(<span class="stringliteral">&#39;Input Image&#39;</span>), plt.xticks([]), plt.yticks([])</div><div class="line">plt.subplot(132),plt.imshow(img_back, cmap = <span class="stringliteral">&#39;gray&#39;</span>)</div><div class="line">plt.title(<span class="stringliteral">&#39;Image after HPF&#39;</span>), plt.xticks([]), plt.yticks([])</div><div class="line">plt.subplot(133),plt.imshow(img_back)</div><div class="line">plt.title(<span class="stringliteral">&#39;Result in JET&#39;</span>), plt.xticks([]), plt.yticks([])</div><div class="line"></div><div class="line">plt.show()</div></div><!-- fragment --><p> Result look like below:</p>
<div class="image">
<img src="../../fft2.jpg" alt="fft2.jpg"/>
<div class="caption">
image</div></div>
<p> The result shows High Pass Filtering is an edge detection operation. This is what we have seen in Image Gradients chapter. This also shows that most of the image data is present in the Low frequency region of the spectrum. Anyway we have seen how to find DFT, IDFT etc in Numpy. Now let's see how to do it in OpenCV.</p>
<p>If you closely watch the result, especially the last image in JET color, you can see some artifacts (One instance I have marked in red arrow). It shows some ripple like structures there, and it is called <b>ringing effects</b>. It is caused by the rectangular window we used for masking. This mask is converted to sinc shape which causes this problem. So rectangular windows is not used for filtering. Better option is Gaussian Windows.</p>
<h2>Fourier Transform in OpenCV </h2>
<p>OpenCV provides the functions <b><a class="el" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d" title="Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating-point array...">cv.dft()</a></b> and <b><a class="el" href="../../d2/de8/group__core__array.html#gaa708aa2d2e57a508f968eb0f69aa5ff1" title="Calculates the inverse Discrete Fourier Transform of a 1D or 2D array. ">cv.idft()</a></b> for this. It returns the same result as previous, but with two channels. First channel will have the real part of the result and second channel will have the imaginary part of the result. The input image should be converted to np.float32 first. We will see how to do it. </p><div class="fragment"><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"><span class="keyword">from</span> matplotlib <span class="keyword">import</span> pyplot <span class="keyword">as</span> plt</div><div class="line"></div><div class="line">img = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<span class="stringliteral">&#39;messi5.jpg&#39;</span>,0)</div><div class="line"></div><div class="line">dft = <a class="code" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d">cv.dft</a>(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)</div><div class="line">dft_shift = np.fft.fftshift(dft)</div><div class="line"></div><div class="line">magnitude_spectrum = 20*np.log(<a class="code" href="../../d2/de8/group__core__array.html#ga6d3b097586bca4409873d64a90fe64c3">cv.magnitude</a>(dft_shift[:,:,0],dft_shift[:,:,1]))</div><div class="line"></div><div class="line">plt.subplot(121),plt.imshow(img, cmap = <span class="stringliteral">&#39;gray&#39;</span>)</div><div class="line">plt.title(<span class="stringliteral">&#39;Input Image&#39;</span>), plt.xticks([]), plt.yticks([])</div><div class="line">plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = <span class="stringliteral">&#39;gray&#39;</span>)</div><div class="line">plt.title(<span class="stringliteral">&#39;Magnitude Spectrum&#39;</span>), plt.xticks([]), plt.yticks([])</div><div class="line">plt.show()</div></div><!-- fragment --><dl class="section note"><dt>Note</dt><dd>You can also use <b><a class="el" href="../../d2/de8/group__core__array.html#gac5f92f48ec32cacf5275969c33ee837d" title="Calculates the magnitude and angle of 2D vectors. ">cv.cartToPolar()</a></b> which returns both magnitude and phase in a single shot</dd></dl>
<p>So, now we have to do inverse DFT. In previous session, we created a HPF, this time we will see how to remove high frequency contents in the image, ie we apply LPF to image. It actually blurs the image. For this, we create a mask first with high value (1) at low frequencies, ie we pass the LF content, and 0 at HF region.</p>
<div class="fragment"><div class="line">rows, cols = img.shape</div><div class="line">crow,ccol = rows/2 , cols/2</div><div class="line"></div><div class="line"><span class="comment"># create a mask first, center square is 1, remaining all zeros</span></div><div class="line">mask = np.zeros((rows,cols,2),np.uint8)</div><div class="line">mask[crow-30:crow+30, ccol-30:ccol+30] = 1</div><div class="line"></div><div class="line"><span class="comment"># apply mask and inverse DFT</span></div><div class="line">fshift = dft_shift*mask</div><div class="line">f_ishift = np.fft.ifftshift(fshift)</div><div class="line">img_back = <a class="code" href="../../d2/de8/group__core__array.html#gaa708aa2d2e57a508f968eb0f69aa5ff1">cv.idft</a>(f_ishift)</div><div class="line">img_back = <a class="code" href="../../d2/de8/group__core__array.html#ga6d3b097586bca4409873d64a90fe64c3">cv.magnitude</a>(img_back[:,:,0],img_back[:,:,1])</div><div class="line"></div><div class="line">plt.subplot(121),plt.imshow(img, cmap = <span class="stringliteral">&#39;gray&#39;</span>)</div><div class="line">plt.title(<span class="stringliteral">&#39;Input Image&#39;</span>), plt.xticks([]), plt.yticks([])</div><div class="line">plt.subplot(122),plt.imshow(img_back, cmap = <span class="stringliteral">&#39;gray&#39;</span>)</div><div class="line">plt.title(<span class="stringliteral">&#39;Magnitude Spectrum&#39;</span>), plt.xticks([]), plt.yticks([])</div><div class="line">plt.show()</div></div><!-- fragment --><p> See the result:</p>
<div class="image">
<img src="../../fft4.jpg" alt="fft4.jpg"/>
<div class="caption">
image</div></div>
 <dl class="section note"><dt>Note</dt><dd>As usual, OpenCV functions <b><a class="el" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d" title="Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating-point array...">cv.dft()</a></b> and <b><a class="el" href="../../d2/de8/group__core__array.html#gaa708aa2d2e57a508f968eb0f69aa5ff1" title="Calculates the inverse Discrete Fourier Transform of a 1D or 2D array. ">cv.idft()</a></b> are faster than Numpy counterparts. But Numpy functions are more user-friendly. For more details about performance issues, see below section.</dd></dl>
<h1>Performance Optimization of DFT </h1>
<p>Performance of DFT calculation is better for some array size. It is fastest when array size is power of two. The arrays whose size is a product of 2’s, 3’s, and 5’s are also processed quite efficiently. So if you are worried about the performance of your code, you can modify the size of the array to any optimal size (by padding zeros) before finding DFT. For OpenCV, you have to manually pad zeros. But for Numpy, you specify the new size of FFT calculation, and it will automatically pad zeros for you.</p>
<p>So how do we find this optimal size ? OpenCV provides a function, <b><a class="el" href="../../d2/de8/group__core__array.html#ga6577a2e59968936ae02eb2edde5de299" title="Returns the optimal DFT size for a given vector size. ">cv.getOptimalDFTSize()</a></b> for this. It is applicable to both <b><a class="el" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d" title="Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating-point array...">cv.dft()</a></b> and <b>np.fft.fft2()</b>. Let's check their performance using IPython magic command timeit. </p><div class="fragment"><div class="line">In [16]: img = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<span class="stringliteral">&#39;messi5.jpg&#39;</span>,0)</div><div class="line">In [17]: rows,cols = img.shape</div><div class="line">In [18]: <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&quot;{} {}&quot;</span>.format(rows,cols))</div><div class="line">342 548</div><div class="line"></div><div class="line">In [19]: nrows = <a class="code" href="../../d2/de8/group__core__array.html#ga6577a2e59968936ae02eb2edde5de299">cv.getOptimalDFTSize</a>(rows)</div><div class="line">In [20]: ncols = <a class="code" href="../../d2/de8/group__core__array.html#ga6577a2e59968936ae02eb2edde5de299">cv.getOptimalDFTSize</a>(cols)</div><div class="line">In [21]: <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&quot;{} {}&quot;</span>.format(nrows,ncols))</div><div class="line">360 576</div></div><!-- fragment --><p> See, the size (342,548) is modified to (360, 576). Now let's pad it with zeros (for OpenCV) and find their DFT calculation performance. You can do it by creating a new big zero array and copy the data to it, or use <b><a class="el" href="../../d2/de8/group__core__array.html#ga2ac1049c2c3dd25c2b41bffe17658a36" title="Forms a border around an image. ">cv.copyMakeBorder()</a></b>. </p><div class="fragment"><div class="line">nimg = np.zeros((nrows,ncols))</div><div class="line">nimg[:rows,:cols] = img</div></div><!-- fragment --><p> OR: </p><div class="fragment"><div class="line">right = ncols - cols</div><div class="line">bottom = nrows - rows</div><div class="line">bordertype = cv.BORDER_CONSTANT <span class="comment">#just to avoid line breakup in PDF file</span></div><div class="line">nimg = <a class="code" href="../../d2/de8/group__core__array.html#ga2ac1049c2c3dd25c2b41bffe17658a36">cv.copyMakeBorder</a>(img,0,bottom,0,right,bordertype, value = 0)</div></div><!-- fragment --><p> Now we calculate the DFT performance comparison of Numpy function: </p><div class="fragment"><div class="line">In [22]: %timeit fft1 = np.fft.fft2(img)</div><div class="line">10 loops, best of 3: 40.9 ms per loop</div><div class="line">In [23]: %timeit fft2 = np.fft.fft2(img,[nrows,ncols])</div><div class="line">100 loops, best of 3: 10.4 ms per loop</div></div><!-- fragment --><p> It shows a 4x speedup. Now we will try the same with OpenCV functions. </p><div class="fragment"><div class="line">In [24]: %timeit dft1= <a class="code" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d">cv.dft</a>(np.float32(img),flags=cv.DFT_COMPLEX_OUTPUT)</div><div class="line">100 loops, best of 3: 13.5 ms per loop</div><div class="line">In [27]: %timeit dft2= <a class="code" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d">cv.dft</a>(np.float32(nimg),flags=cv.DFT_COMPLEX_OUTPUT)</div><div class="line">100 loops, best of 3: 3.11 ms per loop</div></div><!-- fragment --><p> It also shows a 4x speed-up. You can also see that OpenCV functions are around 3x faster than Numpy functions. This can be tested for inverse FFT also, and that is left as an exercise for you.</p>
<h2>Why Laplacian is a High Pass Filter? </h2>
<p>A similar question was asked in a forum. The question is, why Laplacian is a high pass filter? Why Sobel is a HPF? etc. And the first answer given to it was in terms of Fourier Transform. Just take the fourier transform of Laplacian for some higher size of FFT. Analyze it: </p><div class="fragment"><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">from</span> matplotlib <span class="keyword">import</span> pyplot <span class="keyword">as</span> plt</div><div class="line"></div><div class="line"><span class="comment"># simple averaging filter without scaling parameter</span></div><div class="line">mean_filter = np.ones((3,3))</div><div class="line"></div><div class="line"><span class="comment"># creating a gaussian filter</span></div><div class="line">x = <a class="code" href="../../d4/d86/group__imgproc__filter.html#gac05a120c1ae92a6060dd0db190a61afa">cv.getGaussianKernel</a>(5,10)</div><div class="line">gaussian = x*x.T</div><div class="line"></div><div class="line"><span class="comment"># different edge detecting filters</span></div><div class="line"><span class="comment"># scharr in x-direction</span></div><div class="line">scharr = np.array([[-3, 0, 3],</div><div class="line">                   [-10,0,10],</div><div class="line">                   [-3, 0, 3]])</div><div class="line"><span class="comment"># sobel in x direction</span></div><div class="line">sobel_x= np.array([[-1, 0, 1],</div><div class="line">                   [-2, 0, 2],</div><div class="line">                   [-1, 0, 1]])</div><div class="line"><span class="comment"># sobel in y direction</span></div><div class="line">sobel_y= np.array([[-1,-2,-1],</div><div class="line">                   [0, 0, 0],</div><div class="line">                   [1, 2, 1]])</div><div class="line"><span class="comment"># laplacian</span></div><div class="line">laplacian=np.array([[0, 1, 0],</div><div class="line">                    [1,-4, 1],</div><div class="line">                    [0, 1, 0]])</div><div class="line"></div><div class="line">filters = [mean_filter, gaussian, laplacian, sobel_x, sobel_y, scharr]</div><div class="line">filter_name = [<span class="stringliteral">&#39;mean_filter&#39;</span>, <span class="stringliteral">&#39;gaussian&#39;</span>,<span class="stringliteral">&#39;laplacian&#39;</span>, <span class="stringliteral">&#39;sobel_x&#39;</span>, \</div><div class="line">                <span class="stringliteral">&#39;sobel_y&#39;</span>, <span class="stringliteral">&#39;scharr_x&#39;</span>]</div><div class="line">fft_filters = [np.fft.fft2(x) <span class="keywordflow">for</span> x <span class="keywordflow">in</span> filters]</div><div class="line">fft_shift = [np.fft.fftshift(y) <span class="keywordflow">for</span> y <span class="keywordflow">in</span> fft_filters]</div><div class="line">mag_spectrum = [np.log(np.abs(z)+1) <span class="keywordflow">for</span> z <span class="keywordflow">in</span> fft_shift]</div><div class="line"></div><div class="line"><span class="keywordflow">for</span> i <span class="keywordflow">in</span> range(6):</div><div class="line">    plt.subplot(2,3,i+1),plt.imshow(mag_spectrum[i],cmap = <span class="stringliteral">&#39;gray&#39;</span>)</div><div class="line">    plt.title(filter_name[i]), plt.xticks([]), plt.yticks([])</div><div class="line"></div><div class="line">plt.show()</div></div><!-- fragment --><p> See the result:</p>
<div class="image">
<img src="../../fft5.jpg" alt="fft5.jpg"/>
<div class="caption">
image</div></div>
<p> From image, you can see what frequency region each kernel blocks, and what region it passes. From that information, we can say why each kernel is a HPF or a LPF</p>
<h2>Additional Resources </h2>
<ol type="1">
<li><a href="http://cns-alumni.bu.edu/~slehar/fourier/fourier.html">An Intuitive Explanation of Fourier Theory</a> by Steven Lehar</li>
<li><a href="http://homepages.inf.ed.ac.uk/rbf/HIPR2/fourier.htm">Fourier Transform</a> at HIPR</li>
<li><a href="http://dsp.stackexchange.com/q/1637/818">What does frequency domain denote in case of images?</a></li>
</ol>
<h2>Exercises </h2>
</div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:37 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
